<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      //可枚举===》可以被for in遍历到的
      //判断属性是否可枚举Object.getOwnPropertyDescriptor()

      const obj = {
        name: '小明',
        age: 20,
        [Symbol('level')]: '优秀',
        [Symbol('level')]: '有钱',
      }

      const val = Object.getOwnPropertyDescriptor(obj, 'name')

      // console.log(val)

      // {
      //   configurable: true  //是否可以删除
      //   enumerable: true   //属性是否可以枚举
      //   value: '小明'   //属性值
      //   writable: true   //属性是否可以修改
      // }

      Object.defineProperty(obj, 'gender', {
        //直接在对象上定义或者修改属性
        configurable: true,
        enumerable: true,
        value: '男',
        writable: true,
      })
      // console.log(obj)

      // delete obj.gender
      // console.log(obj) //会将新增的属性删除---因为configurable: true
      for (let k in obj) {
        // console.log(obj[k]) //会将枚举属性遍历出来，不包括symbol属性--因为enumerable: true,
      }

      obj.gender = '女'
      // console.log(obj) //修改成功，因为writable: true

      //es6新增的symbol类型--- 当成永远都不会重复的字符串，解决命名问题
      let hd = Symbol('描述符')
      let edu = Symbol()
      // console.log(hd === edu) //symol 永远不等于symbol
      hd.name = 'jerry'
      // console.log(hd.name) //访问不到（当成永远都不会重复的字符串）
      // console.log(hd.toString())
      // console.log(hd.description) //得到描述符

      const obj1 = Object.create({
        bar: 'bar',
      })
      obj1.foo = 'foo'
      Object.defineProperty(obj1, 'name', {
        enumerable: false,
        value: '123',
      })
      obj1[Symbol('age')] = 'age'

      //1.遍历对象的方法--for in --遍历出来了自身枚举属性和原型链上的可枚举属性
      for (let k in obj1) {
        // console.log(obj1[k])   // foo bar
      }

      //配合hasOwnProperty,遍历对象自身的
      for (let k in obj1) {
        // console.log(obj1.hasOwnProperty(k))
        if (obj1.hasOwnProperty(k)) {
          // console.log(obj1[k]) //foo
        }
      }

      //for in 遍历构造函数
      function Person(name) {
        this.name = name
      }
      Person.prototype.getName = function () {
        return this.name
      }
      const p = new Person('jerry')
      for (let key in p) {
        // console.log(p[key]) //jerry  getName()
      }

      //for in 输出的顺序按照k 的小到大（数字）进行排列，字符串和负数按其规则排
      const obj3 = {
        5: '5',
        1: '2',
        a: 'a',
        '-1': '-1',
        3: '3',
        b: 'b',
      }

      for (let key in obj3) {
        // console.log(key, obj3[key])
      }

      //2.Object.keys()  获取对象自身的可枚举的属性,不包含原型链上的可枚举属性和Symbol
      // console.log(Object.keys(obj3)) //返回的是一个数组
      Object.keys(obj3).forEach((item) => {
        // console.log(item, obj3[item])
      })

      //3.Object.getOwnPropertyNames()  获取对象自身的所有属性名，包括不可枚举的属性，不包含原型链上的属性和symbol属性
      let one = Object.getOwnPropertyNames(obj1)
      console.log(one) //foo name
      one.forEach((item) => {
        // console.log(obj1[item])
      })

      //4.获得对象自身的所有symbol属性，不包括原型链上的Symbol
      let four = Object.getOwnPropertySymbols(obj1)
      console.log(four)

      //5. Reflect.ownKeys() //获取对象自身的所有属性，包括不可枚举+Symbol属性
      console.log(Reflect.ownKeys(obj1))
      
    </script>
  </body>
</html>
